/**
 * $Revision: 1.2 $
 * $Date: 2007/06/09 13:25:04 $
 *
 * Copyright (C) 2006 Jive Software. All rights reserved.
 *
 * This software is published under the terms of the GNU Lesser Public License (LGPL),
 * a copy of which is included in this distribution.
 */

package org.jivesoftware;

import java.awt.BorderLayout;


import java.awt.Component;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Image;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.BorderFactory;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JPasswordField;
import javax.swing.JProgressBar;
import javax.swing.JTextField;

import org.jivesoftware.resource.Res;
import org.jivesoftware.smack.AccountManager;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.spark.component.TitlePanel;
import org.jivesoftware.spark.util.DummySSLSocketFactory;
import org.jivesoftware.spark.util.ModelUtil;
import org.jivesoftware.spark.util.ResourceUtils;
import org.jivesoftware.spark.util.SwingWorker;
import org.jivesoftware.sparkimpl.settings.local.LocalPreferences;
import org.jivesoftware.sparkimpl.settings.local.SettingsManager;

import com.regal.reg.RegControler;
import com.regal.reg.UserTypeSelectUi;
import com.regal.reg.VerifyCode;

/**
 * Allows the creation of accounts on an XMPP server.
 */
public class AccountCreationWizard extends JPanel {
    /**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	private JLabel usernameLabel = new JLabel();
    private JTextField usernameField = new JTextField();

    private JLabel passwordLabel = new JLabel();
    private JPasswordField passwordField = new JPasswordField();

    private JLabel confirmPasswordLabel = new JLabel();
    private JPasswordField confirmPasswordField = new JPasswordField();

    private JLabel serverLabel = new JLabel();
    private JTextField serverField = new JTextField("www1.cosoft.org.cn");
    
    private JLabel emailLabel = new JLabel();
    private JTextField emailField = new JTextField();
    
    private JLabel validateLabel = new JLabel();;
    private JTextField validateField = new JTextField();
    private JLabel validateImage;

    private JButton createAccountButton = new JButton();
    private JButton closeButton = new JButton();
    private JButton nextButton = new JButton();

    private JDialog dialog;
    private JFrame parentFrame;

    private boolean registered;
    private VerifyCode vc = new VerifyCode();
    private String expectStr = "0000";
    private XMPPConnection connection = null;
    private JProgressBar progressBar;

    /**
     * Construct the AccountCreationWizard UI.
     */
    public AccountCreationWizard() {
        // Associate Mnemonics
        ResourceUtils.resLabel(usernameLabel, usernameField, Res.getString("label.username") + ":");
        ResourceUtils.resLabel(passwordLabel, passwordField, Res.getString("label.password") + ":");
        ResourceUtils.resLabel(confirmPasswordLabel, confirmPasswordField, Res.getString("label.confirm.password") + ":");
        ResourceUtils.resLabel(serverLabel, serverField, Res.getString("label.server") + ":");
        ResourceUtils.resLabel(emailLabel, emailField, Res.getString("label.email") + ":");
        ResourceUtils.resLabel(validateLabel, validateField, Res.getString("label.validate") + ":");
        ResourceUtils.resButton(createAccountButton, Res.getString("button.create.account"));

        setLayout(new BorderLayout());

        JPanel contentPanel = new JPanel(new GridBagLayout()); //licc
        // Add component to UI
        contentPanel.add(usernameLabel, new GridBagConstraints(0, 0, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
        contentPanel.add(usernameField, new GridBagConstraints(1, 0, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 150, 0));

        contentPanel.add(passwordLabel, new GridBagConstraints(0, 1, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
        contentPanel.add(passwordField, new GridBagConstraints(1, 1, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));

        contentPanel.add(confirmPasswordLabel, new GridBagConstraints(0, 2, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
        contentPanel.add(confirmPasswordField, new GridBagConstraints(1, 2, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));

        contentPanel.add(serverLabel, new GridBagConstraints(0, 3, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
        contentPanel.add(serverField, new GridBagConstraints(1, 3, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));

        contentPanel.add(emailLabel, new GridBagConstraints(0, 4, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
        contentPanel.add(emailField, new GridBagConstraints(1, 4, 3, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
        
        
        expectStr = vc.runVerifyCode(4);
        System.out.println(expectStr);    
        Image im = vc.CreateImage(expectStr);
        validateImage = new JLabel( new ImageIcon(im));
        //validateLabel = new JLabel();
        
        
        contentPanel.add(validateLabel, new GridBagConstraints(0, 5, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
//        add(validateImage, new GridBagConstraints(1, 5, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 1, 0));
//        add(validateField, new GridBagConstraints(2, 5, 2, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 1, 0));
        contentPanel.add(validateField, new GridBagConstraints(1, 5, 2, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0)); //licc
        contentPanel.add(validateImage, new GridBagConstraints(3, 5, 1, 1, 0.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0)); //licc
        
        
        //
        
        
        //
        progressBar = new JProgressBar();


        contentPanel.add(progressBar, new GridBagConstraints(1, 6, 3, 1, 1.0, 0.0, GridBagConstraints.WEST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
        progressBar.setVisible(false);
        
        JPanel directPanel = new JPanel(new BorderLayout());  //licc
        JPanel linePanel = new JPanel(new GridBagLayout());
        JLabel nullLabel = new JLabel();
        nullLabel.setBorder(BorderFactory.createEtchedBorder());
        nullLabel.setPreferredSize(new Dimension(100,2));
        linePanel.add(nullLabel, new GridBagConstraints(0, 0, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.HORIZONTAL, new Insets(5, 5, 5, 5), 0, 0));
        
//        directPanel.add(createAccountButton, new GridBagConstraints(1, 7, 1, 1, 1.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
        ResourceUtils.resButton(closeButton, Res.getString("button.close"));
//        directPanel.add(closeButton, new GridBagConstraints(2, 7, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
        ResourceUtils.resButton(nextButton, Res.getString("button.next"));
//        directPanel.add(nextButton, new GridBagConstraints(3, 7, 1, 1, 0.0, 0.0, GridBagConstraints.EAST, GridBagConstraints.NONE, new Insets(5, 5, 5, 5), 0, 0));
        JPanel buttoonPanel = new JPanel(new FlowLayout(FlowLayout.RIGHT));
//        buttoonPanel.add(createAccountButton);
        buttoonPanel.add(nextButton);
        buttoonPanel.add(closeButton);
        directPanel.add(linePanel, BorderLayout.NORTH);
        directPanel.add(buttoonPanel, BorderLayout.CENTER);
        
        this.add(contentPanel, BorderLayout.CENTER);
        this.add(directPanel, BorderLayout.SOUTH);
        
        createAccountButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                createAccount();
            }
        });
		
        closeButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
                dialog.dispose();
            }
        });
        
        nextButton.addActionListener(new ActionListener() {
            public void actionPerformed(ActionEvent actionEvent) {
            	if(!checkRegParam()){
            		RegControler.getInstance().setUserName(getUsername());
            		RegControler.getInstance().setPasswd(getPassword());
            		RegControler.getInstance().setEmail(getEmail());
            		RegControler.getInstance().setServer(getServer());
            		dialog.setVisible(false);
            		//dialog.dispose();
            		UserTypeSelectUi utSelectPanel = new UserTypeSelectUi();
            		utSelectPanel.invoke(dialog,parentFrame);
            	}
            }
        });
    }

    /**
     * Returns the username to use for the new account.
     *
     * @return the username.
     */
    public String getUsername() {
        return StringUtils.escapeNode(usernameField.getText().toLowerCase());
    }

    /**
     * Returns the password to use for the new account.
     *
     * @return the password to use for the new account.
     */
    public String getPassword() {
        return new String(passwordField.getPassword());
    }
    /**
     * Returns the email to use for the new account.
     *
     * @return the email to use for the new account.
     */
    public String getEmail() {
        return new String(emailField.getText());
    }

    /**
     * Returns the confirmation password to use for the new account.
     *
     * @return the password to use for the new account.
     */
    public String getConfirmPassword() {
        return new String(confirmPasswordField.getPassword());
    }

    /**
     * Returns the server to use with the new account.
     *
     * @return the server to use.
     */
    public String getServer() {
        return serverField.getText();
    }

    /**
     * Returns true if the passwords match.
     *
     * @return true if the passwords match.
     */
    public boolean isPasswordValid() {
        return getPassword().equals(getConfirmPassword());
    }

    public boolean checkRegParam(){    	
    	boolean errors = false;
        String errorMessage = "";
        if(!validateField.getText().equalsIgnoreCase(expectStr))
        {
        	errors = true;
        	validateField.requestFocus();
            errorMessage = Res.getString("message.validate.error");        
        }	

        if (!ModelUtil.hasLength(getUsername())) {
            errors = true;
            usernameField.requestFocus();
            errorMessage = Res.getString("message.username.error");
        }
        else if (!ModelUtil.hasLength(getPassword())) {
            errors = true;
            errorMessage = Res.getString("message.password.error");
        }
        else if (!ModelUtil.hasLength(getConfirmPassword())) {
            errors = true;
            errorMessage = Res.getString("message.confirmation.password.error");
        }
        else if (!ModelUtil.hasLength(getServer())) {
            errors = true;
            errorMessage = Res.getString("message.account.error");
        }
        else if (!isPasswordValid()) {
            errors = true;
            errorMessage = Res.getString("message.confirmation.password.error");
        }

        if (errors) {
            JOptionPane.showMessageDialog(this, errorMessage, Res.getString("title.create.problem"), JOptionPane.ERROR_MESSAGE);
            
        }
    	
        return errors;
    }
    /**
     * Creates the new account using the supplied information.
     */
    private void createAccount() {
        boolean errors = false;
        String errorMessage = "";
        if(!validateField.getText().equalsIgnoreCase(expectStr))
        {
        	errors = true;
        	validateField.requestFocus();
            errorMessage = Res.getString("message.validate.error");        
        }	

        if (!ModelUtil.hasLength(getUsername())) {
            errors = true;
            usernameField.requestFocus();
            errorMessage = Res.getString("message.username.error");
        }
        else if (!ModelUtil.hasLength(getPassword())) {
            errors = true;
            errorMessage = Res.getString("message.password.error");
        }
        else if (!ModelUtil.hasLength(getConfirmPassword())) {
            errors = true;
            errorMessage = Res.getString("message.confirmation.password.error");
        }
        else if (!ModelUtil.hasLength(getServer())) {
            errors = true;
            errorMessage = Res.getString("message.account.error");
        }
        else if (!isPasswordValid()) {
            errors = true;
            errorMessage = Res.getString("message.confirmation.password.error");
        }

        if (errors) {
            JOptionPane.showMessageDialog(this, errorMessage, Res.getString("title.create.problem"), JOptionPane.ERROR_MESSAGE);
            return;
        }

        final Component ui = this;
        progressBar.setIndeterminate(true);
        progressBar.setStringPainted(true);
        progressBar.setString(Res.getString("message.registering", getServer()));
        progressBar.setVisible(true);

        final SwingWorker worker = new SwingWorker() {
            int errorCode;


            public Object construct() {
                try {
                    //createAccountButton.setEnabled(false);
                    connection = getConnection();
                }
                catch (XMPPException e) {
                    return e;
                }
                try {
                    final AccountManager accountManager = new AccountManager(connection);
                    accountManager.createAccount(getUsername(), getPassword(), getEmail());
                }
                catch (XMPPException e) {
                    XMPPError error = e.getXMPPError();
                    if (error != null) {
                        errorCode = error.getCode();
                    }
                    else {
                        errorCode = 500;
                    }

                }
                return "ok";
            }

            public void finished() {
                progressBar.setVisible(false);
                if (connection == null) {
                    if (ui.isShowing()) {
                        //createAccountButton.setEnabled(true);
                        JOptionPane.showMessageDialog(ui, Res.getString("message.connection.failed", getServer()), Res.getString("title.create.problem"), JOptionPane.ERROR_MESSAGE);
                        //createAccountButton.setEnabled(true);
                    }
                    return;
                }

                if (errorCode == 0) {
                    accountCreationSuccessful();
                }
                else {
                    accountCreationFailed(errorCode);
                }
            }
        };

        worker.start();
    }

    /**
     * Called if the account creation failed.
     *
     * @param errorCode the error code.
     */
    private void accountCreationFailed(int errorCode) {
        String message = Res.getString("message.create.account");
        if (errorCode == 409) {
            message = Res.getString("message.already.exists");
            usernameField.setText("");
            usernameField.requestFocus();
        }
        JOptionPane.showMessageDialog(this, message, Res.getString("title.create.problem"), JOptionPane.ERROR_MESSAGE);
        //createAccountButton.setEnabled(true);
    }

    /**
     * Called if the account was created succesfully.
     */
    private void accountCreationSuccessful() {
        registered = true;
        JOptionPane.showMessageDialog(this, Res.getString("message.account.created"), Res.getString("title.account.created"), JOptionPane.INFORMATION_MESSAGE);
        dialog.dispose();
    }

    /**
     * Invokes the AccountCreationWizard.
     *
     * @param parent the parent frame to use.
     */
    public void invoke(JFrame parent) {
        dialog = new JDialog(parent, Res.getString("title.create.new.account"), true);
        parentFrame = parent;
//        TitlePanel titlePanel = new TitlePanel(Res.getString("title.account.create.registration"), Res.getString("message.account.create"), null, true); //licc        
        TitlePanel titlePanel = new TitlePanel(new String[]{Res.getString("title.create.step1"),Res.getString("title.create.step2"),Res.getString("title.create.step3")}, TitlePanel.FOCUS_FROM0_0);
        dialog.getContentPane().setLayout(new BorderLayout());
        dialog.getContentPane().add(titlePanel, BorderLayout.NORTH);
        dialog.getContentPane().add(this, BorderLayout.CENTER);
        dialog.pack();
        dialog.setSize(450, 350);
        dialog.setLocationRelativeTo(parentFrame);
        dialog.setVisible(true);
    }

    /**
     * Creates an XMPPConnection based on the users settings.
     *
     * @return the XMPPConnection created.
     * @throws XMPPException thrown if an exception occured creating the connection.
     */
    private XMPPConnection getConnection() throws XMPPException {
        final LocalPreferences localPreferences = SettingsManager.getLocalPreferences();
        XMPPConnection connection = null;

        // Get connection

        int port = localPreferences.getXmppPort();

        String serverName = getServer();

        int checkForPort = serverName.indexOf(":");
        if (checkForPort != -1) {
            String portString = serverName.substring(checkForPort + 1);
            if (ModelUtil.hasLength(portString)) {
                // Set new port.
                port = Integer.valueOf(portString);
            }
        }

        boolean useSSL = localPreferences.isSSL();
        boolean hostPortConfigured = localPreferences.isHostAndPortConfigured();

        ConnectionConfiguration config = null;

        if (useSSL) {
            if (!hostPortConfigured) {
                config = new ConnectionConfiguration(serverName, 5223);
                config.setSocketFactory(new DummySSLSocketFactory());
            }
            else {
                config = new ConnectionConfiguration(localPreferences.getXmppHost(), port, serverName);
                config.setSocketFactory(new DummySSLSocketFactory());
            }
        }
        else {
            if (!hostPortConfigured) {
                config = new ConnectionConfiguration(serverName);
            }
            else {
                config = new ConnectionConfiguration(localPreferences.getXmppHost(), port, serverName);
            }


        }

        if (config != null) {
            config.setReconnectionAllowed(true);
            boolean compressionEnabled = localPreferences.isCompressionEnabled();
            config.setCompressionEnabled(compressionEnabled);
            connection = new XMPPConnection(config);
        }

        if (connection != null) {
            connection.connect();
        }
        return connection;

    }

    /**
     * Returns true if the user is registered.
     *
     * @return true if the user is registered.
     */
    public boolean isRegistered() {
        return registered;
    }
}

